#include "SVD.h"

SVD* SVD::instance = NULL;
int SVD::dimension = 0;

SVD::SVD() {

}

SVD* SVD::getInstance() {
	if (instance == NULL)
		instance = new SVD();
	return instance;
}

SVD::~SVD() {
	if (instance != NULL)
		delete instance;
}

void SVD::setPath(string path) {
	this->path = path;
}

// Este metodo genera las matrices reducidas y las guarda en disco en this->path.
void SVD::calculate(ArchivoAuxiliar* file,unsigned int nDocs,unsigned int nTerminos) {

	mat matriz(nTerminos, nDocs);
	matriz.zeros();

	cout << "Calculando matriz, Terminos: "<<nTerminos<<"Docs: "<<nDocs<<endl<<endl;

	ArchivoTerminos* t = new ArchivoTerminos("Nombre");
	unsigned int row = 0;
	file->clear();
	file->seekg(0, ios::beg);
	RegistroAuxiliar *reg=NULL;
	reg = new RegistroAuxiliar();
	int regPointer = file->read(reg);


	while (regPointer!=RES_EOF) {

		cout<<"Termino: "<<reg->getTermino()<<endl;
		vector<uint32_t> *docs = reg->getNroDocs();
		vector<uint16_t> *frec = reg->getFrecuencias();
		unsigned int gi = 1;
		unsigned int gfi = 0;
		for (unsigned int i = 0; i < frec->size(); i++) {
			gfi += frec->at(i);
		}

		for (unsigned int j = 0; j < docs->size(); j++) {
			uint32_t doc = docs->at(j)-1;
			uint16_t fre = frec->at(j);
			unsigned int pij = fre / gfi;
			float li = log(fre + 1);
			matriz(row,doc)=li;
			gi += ((pij * log(pij)) / log(nDocs));
		}
		colvec colGlobal(nTerminos);
		colGlobal.zeros();
		colGlobal(1)=gi;
		//t->add(reg->getTermino(), row, gi);
		row++;
		delete (reg);
		reg = new RegistroAuxiliar();
		regPointer =file->read(reg);
	}

	delete (t);
	matriz.print("X: ");

	mat T;
	vec S;
	mat D;
	svd(T,S,D,matriz);

	cout<<"Dimension: "<<dimension<<endl;
	//Ahora trunco las matrices al numero de dimensiones pedido
	T=T.cols(0,dimension);
	D=D.rows(0,dimension);
	S=S.rows( 0, dimension);


	T.print("T: ");
	S.print("S: ");
	D.print("D: ");


	//Guardo las matrices a disco
	T.save("T.bin", arma_binary);
	D.save("D.bin", arma_binary);
	S.save("S.bin", arma_binary);
}
